Selectors API 是 W3C 推荐标准,规定了浏览器原生支持的 CSS 查询 API,其核心是两个方法:querySelector() 和 querySelectorAll(),Document 类型和 Element 类型的实例上都会暴露这两个方法。
querySelector() 方法接收 CSS 选择符参数,返回匹配该模式的第一个后代元素,如果没有匹配项则返回 null。
// 取得<body>元素
let body = document.querySelector("body");
// 取得 ID 为"myDiv"的元素
let myDiv = document.querySelector("#myDiv");
// 取得类名为"selected"的第一个元素
let selected = document.querySelector(".selected");
// 取得类名为"button"的图片
let img = document.body.querySelector("img.button");
querySelectorAll() 也接收一个用于查询的参数,但它会返回所有匹配的节点,这个方法返回的是一个 NodeList 的静态实例,如果没有匹配项,则返回空的 NodeList 实例。querySelectorAll() 返回的 NodeList 实例是一个静态的“快照”,而非“实时”的查询。
// 取得 ID 为"myDiv"的<div>元素中的所有<em>元素
let ems = document.getElementById("myDiv").querySelectorAll("em");
// 取得所有类名中包含"selected"的元素
let selecteds = document.querySelectorAll(".selected");
// 取得所有是<p>元素子元素的<strong>元素
let strongs = document.querySelectorAll("p strong");
matches() 方法接收一个 CSS 选择符参数,如果元素匹配则返回 true,否则返回 false。
if (document.body.matches("body.page1")){
// true
}
Element Traversal API 为 DOM 元素添加了 5 个属性:
HTML5 增加了一些特性以方便使用 CSS 类:
getElementsByClassName() 方法接收一个参数,即包含一个或多个类名的字符串,返回类名中包含相应类的元素的 NodeList。
// 取得所有类名中包含"username"和"current"元素
// 这两个类名的顺序无关紧要
let allCurrentUsernames = document.getElementsByClassName("username current");
// 取得 ID 为"myDiv"的元素子树中所有包含"selected"类的元素
let selected = document.getElementById("myDiv").getElementsByClassName("selected");
要操作类名,可以通过 className 属性实现添加、删除和替换。以下面代码为例:
<div class="bd user disabled">...</div>
这个
// 要删除"user"类
let targetClass = "user";
// 把类名拆成数组
let classNames = div.className.split(/\s+/);
// 找到要删除类名的索引
let idx = classNames.indexOf(targetClass);
// 如果有则删除
if (idx > -1) {
classNames.splice(i,1);
}
// 重新设置类名
div.className = classNames.join(" ");
HTML5 通过给所有元素增加 classList 属性为这些操作提供了更简单也更安全的实现方式。classList 是一个集合类型 DOMTokenList 实例,具有以下方法:
通过操作 classList 属性,之前的代码可以简化成一行:
div.classList.remove("user");
HTML5 增加了辅助 DOM 焦点管理的功能。document.activeElement 始终包含当前拥有焦点的 DOM 元素。例如:
let button = document.getElementById("myButton");
button.focus();
console.log(document.activeElement === button); // true
focus() 方法可以让某个元素获取焦点,document.hasFocus() 方法返回布尔值,表示文档是否拥有焦点:
let button = document.getElementById("myButton");
button.focus();
console.log(document.hasFocus()); // true
document.readyState 属性用于判断文档是否加载完毕,它包含两个值:loading,表示文档正在加载;complete,表示文档加载完成。
HTML5 增加了 document.head 属 性,指向文档的
元素:let head = document.head;
characterSet 属性表示文档实际使用的字符集,也可以用来指定新字符集:
console.log(document.characterSet); // "UTF-16"
document.characterSet = "UTF-8";
HTML5 允许给元素指定非标准的属性,但要使用前缀 data-以便告诉浏览器,这些属性既不包含与渲染有关的信息,也不包含元素的语义信息:
<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
定义了自定义数据属性后,可以通过元素的 dataset 属性来访问:
let div = document.getElementById("myDiv");
// 取得自定义数据属性的值
let appId = div.dataset.appId;
let myName = div.dataset.myname;
// 设置自定义数据属性的值
div.dataset.appId = 23456;
div.dataset.myname = "Michael";
// 有"myname"吗?
if (div.dataset.myname){
console.log(`Hello, ${div.dataset.myname}`);
}
HTML5 可以通过 innerHTML 属性向文档中读取或者插入整段的 HTML 代码, 例如如下代码:
<div id="content">
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
对于这里的
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
在写入模式下,赋给 innerHTML 属性的值会被解析为 DOM 子树,并替代元素之前的所有节点,如果赋值中不包含任何 HTML 标签,则直接生成一个文本节点。
div.innerHTML = "Hello world!";
// 包含 HTML 字符时
div.innerHTML = "Hello & welcome, <b>\"reader\"!</b>";
HTML5还提供 outerHTML 属性进行类似操作,区别在于,读取 outerHTML 属性时,会返回调用它的元素(及所有后代元素)的 HTML 字符串。在写入 outerHTML 属性时,调用它的元素会被传入的 HTML 字符串经解释之后生成的 DOM 子树取代。上述 HTML 代码中的
div.outerHTML = "<p>This is a paragraph.</p>";
则新的
元素会取代原来的
为了防止 XSS 攻击,如果页面中要使用用户提供的信息,则不建议使用 innerHTML。
scrollIntoView() 方法存在于所有 HTML 元素上,可以滚动浏览器窗口或容器元素以便包含元素进入视口。这个方法的参数如下:
// 确保元素可见
document.forms[0].scrollIntoView();
// 同上
document.forms[0].scrollIntoView(true); document.forms[0].scrollIntoView({block: 'start'});
// 尝试将元素平滑地滚入视口
document.forms[0].scrollIntoView({behavior: 'smooth', block: 'start'});
HTML5 还有两个常用属性:innerText 和 outerText。innerText 属性对应元素中包含的所有文本内容,在用于读取值时,innerText 会按照深度优先的顺序将子树中所有文本节点的值拼接起来。在用于写入值时,innerText 会移除元素的所有后代并插入一个包含该值的文本节点。
<div id="content">
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</div>
对这个例子中的
This is a paragraph with a list following it.
Item 1
Item 2
Item 3
对
div.innerText = "Hello world!";
页面中的
<div id="content">Hello world!</div>
outerText 与 innerText 是类似的,只不过作用范围包含调用它的节点。读取文本值时,outerText 与 innerText 实际上会返回同样的内容。 写入文本值时,outerText 会替换整个元素。